#ifndef TERN_DEFS_H
#define TERN_DEFS_H

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <ext/hash_map>

using namespace __gnu_cxx;

// Some important system settings. Need to move to Prof's option config file.
#define MEMOIZER_ORDER
#define REPLAYER_ORDER

#ifdef MEMOIZER_ORDER
#define HANDLE_SLEEP			
#define ENFORCE_WINDOW
#endif

// Heming: TERN internal settings, do not involve setting in option config file.
#define MAX_THREAD_NUM 100
#define MYSQLD_PKT_LEN 300
#define SLEEP_TIME 10000
#define FULL_FACTOR 0.8
#define TINY_SIZE 32
#define SMALL_SIZE 1024
#define BASIC_SIZE 1024
#define LONG_SIZE 30*1024
#define RECORD_SIZE BASIC_SIZE
#define SCHED_TRUNK_MAX_SIZE 30000
#define INST_CNT_INTERVAL 3000000
#define PROCESS_NUM 32768
#define INST_SIZE 170000
#define MAX_SCHEDULE_NUM 600
#define GOOD_WINDOW_THRESHOLD 0.5												// finishing rate is bigger than 0.5.
#define EXCEPTIONAL_TASK_INTERVAL		3											// If a task is not ended within this interval (sec), it is exceptional.
#define START_OFFSET -2
#define TRACK_FAIL_TRIES_LIMIT 10
#define TRACK_WAIT_INTERVAL 1															// 1 second.

#define WRITE_LOCKED 100000																// The read lock accumulated count can not be high than this, so this value is fine.
#define SOCKET_SYNC_VAR_BASE 0xff000000
#define SLEEP_SYNC_VAR -2
#define INVALID_TID_FOR_PTHREAD_CREATE -3
#define WINDOW_SYNC_VAR -4
#define SYS_ACCEPT      5																				// This is the same as the def in uclibc.
#define ADDR_OFFSET 4																					// for 32 bit machine.
#define LANDMARK_HOOK_ARG_SIZE 3
#define RANDOM_BAD_CONSTANT 0X0

#define START_TASK_LANDMARK "tern_task_start"
#define END_TASK_LANDMARK "tern_task_end"
#define TERN_SYMBOLIC_LANDMARK "tern_symbolic"
#define TERN_TIMEDWAIT_BEFORE "pthread_cond_timedwait}{before"
#define TERN_TIMEDWAIT_AFTER "pthread_cond_timedwait}{after"
#define TERN_CONDWAIT_BEFORE "pthread_cond_wait}{before"
#define TERN_CONDWAIT_AFTER "pthread_cond_wait}{after"

// This section must be updated once landmarks[] at TernLandmark.h has been updated.
#define TERN_LANDMARKS_NUM 48
#define PTHREAD_CREATE_LANDMARK_IDX 5
#define PTHREAD_COND_WAIT_IDX 9
#define PTHREAD_COND_TIMEDWAIT_IDX 10
#define TERN_PTHREAD_MUTEX_LOCK_IDX 1
#define START_TASK_LANDMARK_IDX 21
#define END_TASK_LANDMARK_IDX 22
#define TERN_SYMBOLIC_LANDMARK_IDX 27
#define TERN_USLEEP_LANDMARK_IDX 15
#define TERN_PTHREAD_EXIT_LANDMARK_IDX 7

#define TERN_BEFORE_LANDMARK "tern_before_landmark"
#define TERN_AFTER_LANDMARK "tern_after_landmark"
#define CONSTRAINT_FILENAME "%s/cst-%d-Tid-%d-%d.pc"
#define TRUNK_TID_FILENAME "Tid-%d-%u-%d-%d.txt"
#define TRUNK_CST_FILENAME "Cst-%d-%u-%d-%d.txt"
#define HIGHLIGHT_STR_BEFORE	"\n\n**************************************************************************\n"
#define HIGHLIGHT_STR_AFTER		"**************************************************************************\n\n\n"

// for printf and fprintf to print uint64_t.
#if __WORDSIZE == 64
#define U64 "%lu"
#define X64 "%lx"
#else
#define U64 "%llu"
#define X64 "%llx"
#endif


typedef volatile long atomic_t;
typedef hash_map<int, int> Long_To_Int_Map;
typedef hash_map<int, int> Int_To_Int_Map;
typedef hash_map<int, time_t> Int_To_Time_Map;
typedef hash_map<int, int> Inst_To_IID_Map;
typedef hash_map<int, pthread_cond_t *> Int_To_Cond_Var_Map;
typedef hash_map<const char *, char *> Sym_Var_To_Value_Map;

struct eqstr {
	bool operator()(const char* s1, const char* s2) const {
		return strcmp(s1, s2) == 0;
	}
};

typedef __gnu_cxx::hash_map<const char*, int, 
                            __gnu_cxx::hash<const char*>, eqstr> Char_Ptr_To_Int_Map;

typedef enum {
	OpMisMatch = -4,
	TaskStart = -3,
	SchedFinish = -2,
	UnKnown = -1,
	OK = 0
} MoveOnRet;

#include "options.h"
#include "tern-options.h"

// YJF: can be made faster if need be
#define DUMP_DIR          (get_option(tern, dump_dir))
#define INPUT             (get_option(tern, input))
#define REFERENCE_LOG     (get_option(tern, reference_log))
#define SYNC_LOG          (get_option(tern, sync_log))
#define ORDER_LOG         (get_option(tern, order_log))
#define TERN_SYNC_LOG      (get_option(tern, tern_sync_log))
#define BROKEN_ORDER_LOG  (get_option(tern, broken_order_log))
#define GOOD_ORDER_LOG    (get_option(tern, good_order_log))
#define GOOD_WINDOW_LOG   (get_option(tern, good_finished_windows))
#define REPLAY_STAT_LOG   (get_option(tern, replay_stat_log))

// For dumping constraints and schedules to the file when we do not enforce any order at recording part.
#define NO_ORDER_LOG    (get_option(tern, good_order_log))						

// Heming
#define IS_BATCH_PROGRAM			(get_option(tern, is_batch_program))
#define RECORD_MEM_ACCESS		(get_option(tern, record_mem_access))
#define TASK_WINDOW_SIZE 		(unsigned)(get_option(tern, window_size))
#define REPLAY_EXPIRE_TIME		(get_option(tern, replay_expire_time))
#define	PRINT_FINISH_SCHED_INFO (get_option(tern, print_finish_sched_info)) 
#define	PRINT_BROKEN_SCHED_INFO (get_option(tern, print_broken_sched_info)) 

#define	REPLAYER_USE_WAIT_FLAG (get_option(tern, replayer_use_wait_flag))
#define	REPLAYER_LOAD_CACHE (get_option(tern, replayer_load_cache))
#define MEMOIZER_SIMPLIFY_EXPR (get_option(tern, memoizer_simplify_expr))
#define	MEMOIZER_CONDITION_SLICING (get_option(tern, memoizer_condition_slicing))
#define	IS_MYSQLD (get_option(tern, is_mysqld))
// Jingyue: Record on failure
#define RECORD_ON_FAILURE (get_option(tern, record_on_failure))

// Debugging options
#define MEMOIZER_PRINT_EXECUTE_CALL (get_option(tern, memoizer_print_execute_call))
#define REPLAYER_PRINT_DEBUG_INFO (get_option(tern, replayer_print_debug_info))
#define REPLAYER_CHECK_HOOK_ID (get_option(tern, replayer_check_hook_id))
#define REPLAYER_USE_SCHED_TRACK (get_option(tern, replayer_use_sched_track))

#define rp_dbg(args...) if (REPLAYER_PRINT_DEBUG_INFO) {fprintf(stderr, args);fflush(stderr);}

static inline FILE *xfopen(const char* path, const char* mode) 
{
        FILE *f;
        f = fopen(path, mode);
        if(!f) {
                fprintf(stderr, "cannot open file %s: %s!\n", 
                        path, strerror(errno)); // YJF: thread-unsafe
                abort();
        }
        return f;
}

#endif

